package aim;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * InputFile.java
 * 
 * This class represents an input file. It is used mainly to store information
 * about a file converning characters, words, and lines.
 * 
 * @author Zachary M. Allen
 * @author Andrew Bernard
 */
public class InputFile {
	
	/**
	 * File that this object represents
	 */
	private File file;
	
	/**
	 * Word count of file
	 */
	private int wordCount;
	
	/**
	 * Line count of file
	 */
	private int lineCount;
		
	/**
	 * Bitmask of each line
	 */
	private int[] bitmasks;

	/**
	 * Length of longest line
	 */
	private int longestLine;
	
	/**
	 * Getter returns value of longest line
	 * @return    Current value of longest line
	 */
	public int getLongestLine() {
		return longestLine;
	}

	/**
	 * Get the value of a bitmask
	 * @param    index    Index of bitmask to return
	 * @return    Bitmask at given index
	 */
	public int getBitmask(int index) {
		return bitmasks[index];
	}

	/**
	 * Constructor
	 * @param    fileName    File name
	 * @throws    IOException
	 */
	public InputFile(String fileName) throws IOException {
		file = new File(fileName);
		lineCount = countLines();
		bitmasks = new int[lineCount];		
	}

	/**
	 * Counts the number of lines in the file. Also used to set the longest
	 * line length
	 * @return    Number of lines in file
	 * @throws    IOException
	 */
	private int countLines() throws IOException {
		
		int lineCount = 0;
		int currentLineLength = 0;
		int longestLineLength = 0;
		int nextChar = 0;
		
		BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));
		
		nextChar = fis.read();
		while (nextChar != Constants.EOF) {
			
			currentLineLength++;
			
			if (nextChar == Constants.CR) {				
				int temp = Constants.peek(fis);
				if (temp == Constants.LF) {
					fis.skip(1);
					currentLineLength++;
				}
			}
			
			if (nextChar == Constants.CR || nextChar == Constants.LF) {
				lineCount++;
				if (currentLineLength > longestLineLength) {
					longestLineLength = currentLineLength;
				}
				currentLineLength = 0;
			}
			
			nextChar = fis.read();
			
		}
		longestLine = longestLineLength;
		return lineCount;
	}

	/**
	 * Getter returns value of charCount
	 * @return    Current value of charCount
	 */
	public long getCharCount() {
		return file.length();
	}
	
	/**
	 * Setter sets value of wordCount
	 * @param    wordCount    New value of wordCount
	 */
	public void setWordCount(int wordCount) {
		this.wordCount = wordCount;
	}

	/**
	 * Getter returns value of wordCount
	 * @return    Current value of wordCount
	 */
	public int getWordCount() {
		return wordCount;
	}
	
	/**
	 * Getter returns value of lineCount
	 * @return    Current value of lineCount
	 */
	public int getLineCount() {
		return lineCount;
	}

	/**
	 * Getter returns value of file
	 * @return    Current value of file
	 */
	public File getFile() {
		return file;
	}

	/**
	 * Returns the number of bitmasks
	 * @return    Current number of bitmasks
	 */
	public int getNumBitmasks() {
		return bitmasks.length;
	}

	/**
	 * Processes a word, setting the appropriate bits in the line's bitmask
	 * @param    line    Line to add to
	 * @param    word    Word to add
	 */
	public void processWord(int line, String word) {
		int bitOne = Math.abs(word.hashCode() % Constants.DEFAULT_BITS_PER_BITMASK);
		int bitTwo = Math.abs((word.hashCode() * (line + 2)) % Constants.DEFAULT_BITS_PER_BITMASK);
		int bitThree = Math.abs((word.hashCode() / (line + 2)) % Constants.DEFAULT_BITS_PER_BITMASK);
		
		if( line >= bitmasks.length ) {
		    return;
		}
		bitmasks[line] = bitmasks[line] | (1 << bitOne);
		bitmasks[line] = bitmasks[line] | (1 << bitTwo);
		bitmasks[line] = bitmasks[line] | (1 << bitThree);

	}

}
